/*
 * @(#)QueryRequest.java
 * Date 2013-08-27
 * Version 1.0
 * Author Jim Horner
 * Copyright (c)2012
 */


package us.hornerscorners.lamppost.registry.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import us.hornerscorners.lamppost.registry.config.QueryMethodConfig;
import us.hornerscorners.lamppost.registry.config.QueryParameterConfig;

import us.hornerscorners.lamppost.registry.constant.IQueryName;
import us.hornerscorners.lamppost.registry.constant.QuerySlotName;


/**
 *
 * @author jim
 */
public class QueryRequest {

    /** Field description */
    private final String homeCommunityId;

    /** Field description */
    private final QueryMethodConfig queryMethodConfig;

    /** Field description */
    private final Map<QuerySlotName, List<QueryParameter>> queryParameters;

    /** Field description */
    private final QueryReturnType returnType;

    /**
     * Constructs ...
     *
     *
     * @param homeCommunityId
     * @param queryMethodConfig
     * @param returnType
     */
    public QueryRequest(String homeCommunityId, QueryMethodConfig queryMethodConfig,
                        QueryReturnType returnType) {

        super();

        this.homeCommunityId = homeCommunityId;
        this.queryMethodConfig = queryMethodConfig;
        this.returnType = returnType;
        this.queryParameters = new HashMap<>();
    }

    /**
     * Method description
     *
     *
     * @param parameter
     */
    public void addParameter(QueryParameter parameter) {

        QuerySlotName name = parameter.getSlotName();

        if (this.queryParameters.containsKey(name)) {

            this.queryParameters.get(name).add(parameter);

        } else {

            List<QueryParameter> paramList = new ArrayList<>();

            paramList.add(parameter);
            this.queryParameters.put(name, paramList);
        }
    }

    /**
     * Method description
     *
     *
     * @param param
     *
     * @return
     */
    public boolean containsParameter(QueryParameter param) {

        return this.queryParameters.containsKey(param.getSlotName());
    }

    /**
     * Method description
     *
     *
     * @param slotName
     *
     * @return
     */
    public String getFirstParameterValue(QuerySlotName slotName) {

        String result = null;

        if (this.queryParameters.containsKey(slotName)) {

            List<QueryParameter> qparams = this.queryParameters.get(slotName);

            if (qparams.isEmpty() == false) {

                List<String> qvalues = qparams.get(0).getValues();

                if (qvalues.isEmpty() == false) {

                    result = qvalues.get(0);
                }
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param slotName
     *
     * @return
     */

    public List<String> getFirstSlotValues(QuerySlotName slotName) {

        List<String> result = new ArrayList<>();

        if (this.queryParameters.containsKey(slotName)) {

            List<QueryParameter> qparams = this.queryParameters.get(slotName);

            if (qparams.isEmpty() == false) {

                result.addAll(qparams.get(0).getValues());
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public String getHomeCommunityId() {
        return homeCommunityId;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public String getMethodName() {

        return this.queryMethodConfig.getQueryName().getName();
    }

    /**
     * Method description
     *
     *
     *
     * @return
     */
    public List<QueryParameter> getParameters(QuerySlotName slotName) {

        List<QueryParameter> result = new ArrayList<>();

        if (this.queryParameters.containsKey(slotName)) {

            result.addAll(this.queryParameters.get(slotName));
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public QueryMethodConfig getQueryMethodConfig() {
        return queryMethodConfig;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public IQueryName getQueryName() {

        return this.queryMethodConfig.getQueryName();
    }

    /**
     * Method description
     *
     *
     * @param slotName
     *
     * @return
     */
    public QueryParameterConfig getQueryParameterConfig(QuerySlotName slotName) {

        return this.queryMethodConfig.findParameterConfig(slotName);
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public QueryReturnType getReturnType() {
        return returnType;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public List<QuerySlotName> getSlotNames() {

        List<QuerySlotName> result = new ArrayList<>();

        result.addAll(this.queryParameters.keySet());

        return result;
    }

    /**
     * Method description
     *
     *
     * @param slotName
     *
     * @return
     */
    public boolean hasMultipleSlotValues(QuerySlotName slotName) {

        boolean result = false;

        if (this.queryParameters.containsKey(slotName)) {

            List<QueryParameter> slotParams = this.queryParameters.get(slotName);

            if (slotParams.size() > 1) {

                result = true;

            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param slotName
     *
     * @return
     */
    public boolean hasMultipleValues(QuerySlotName slotName) {

        boolean result = false;

        if (hasMultipleSlotValues(slotName) == false) {

            if (this.queryParameters.containsKey(slotName)) {

                for (QueryParameter qparam : this.queryParameters.get(slotName)) {

                    if (qparam.getValues().size() > 1) {

                        result = true;

                        break;
                    }
                }
            }

        } else {

            result = true;
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param slotName
     *
     * @return
     */
    public boolean hasNoValues(QuerySlotName slotName) {

        return (hasValues(slotName) == false);
    }

    /**
     * Method description
     *
     *
     * @param slotName
     *
     * @return
     */
    public boolean hasValues(QuerySlotName slotName) {

        boolean result = false;

        if (this.queryParameters.containsKey(slotName)) {

            QueryParameterConfig cfg = getQueryParameterConfig(slotName);

            if (cfg.isMultipleAllowed()) {

                result = (getFirstSlotValues(slotName).isEmpty() == false);

            } else if (cfg.isAndOrSupported()) {

                for (QueryParameter qparam : this.queryParameters.get(slotName)) {

                    if (qparam.getValues().isEmpty() == false) {

                        result = true;

                        break;
                    }
                }

            } else {

                result = StringUtils.isNotBlank(getFirstParameterValue(slotName));
            }
        }

        return result;
    }
}
